﻿#include "uimodeltreeview.h"

#include <QHeaderView>
#include <QPainter>
#include <QPainterPath>
#include <QColor>
#include <QMenu>
#include <QAction>
#include <QFileDialog>
#include <QtConcurrent>
#include <QFuture>
#include <QMap>
#include <QFile>

#include <shlib/quc_sdk/customwidget/uicustomdialog.h>
#include <shlib/cwebrequestapi.h>
#include <shlib/quc_sdk/iconhelper/icon_helper.h>
#include <login/cuserinfomgr.h>

#include <ElaProgressBar.h>
#include <ElaComboBox.h>
#include <ElaLineEdit.h>
#include <ElaIconButton.h>
#include <ElaContentDialog.h>
#include <ElaText.h>



#include <shlib/iottypedef.h>



UiModelTreeView::UiModelTreeView(QWidget *parent)
    : ElaTreeView{parent},m_viewModel(new QStandardItemModel)
{
    reload();
    this->setEditTriggers(QAbstractItemView::NoEditTriggers);
    //this->setItemDelegate(new UiModelTreeItemDelegate(this, this));
    this->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(this, &UiModelTreeView::customContextMenuRequested,
            this, [&](const QPoint &pos){
        QMenu menu;

        // 添加动作
        QAction *addAction = menu.addAction("添加模型");
        QAction *action2 = menu.addAction("删除");
        // connect(action2, &QAction::triggered, this, [&](){
        //     QtConcurrent::run([this]() { onImportSig(); });
        // });

        // 连接动作到槽函数
        connect(addAction, &QAction::triggered, this, &UiModelTreeView::onAddModel);

        // 显示菜单
        menu.exec(mapToGlobal(pos));
    });

    connect(this, &UiModelTreeView::doubleClicked, this, [&](const QModelIndex &index){
        if(!index.isValid())
            return;

        ENodelLevel level = index.data(ENodeValueRole::NodelLevel).value<ENodelLevel>();
        if(Root == level) {
            return;
        }

        QString modelName = index.data(Qt::DisplayRole).toString();
        if(!m_models.contains(modelName))
            return;

        emit sigSelectModelChange(m_models[modelName]);
    });
}

void UiModelTreeView::reload() {

    m_models.clear();
    m_viewModel->clear();

    /*读取所有模型*/
    QList<QSharedPointer<CModelInfo>> modelList;
    if(!CWebRequestApi::ins().getModelList(modelList))
        return;

    for(auto& it : modelList) {
        m_models.insert(it->name, it);
        viewAddModel(it);
    }

    this->header()->hide();
    this->setModel(m_viewModel);
}

void UiModelTreeView::onAddModel() {
    QStringList groupNames;
    for(int row = 0; row < m_viewModel->rowCount(); ++row) {
        groupNames.append(m_viewModel->item(row)->data(Qt::DisplayRole).toString());
    }

    QVBoxLayout layout;

    ElaText lab_group("选择分组:");
    QFont font = lab_group.font();
    font.setPointSize(14);
    lab_group.setFixedSize(100, 30);
    lab_group.setFont(font);
    ElaComboBox groupBox;
    groupBox.setFixedHeight(30);
    groupBox.addItems(groupNames);
    groupBox.setEditable(true);
    QHBoxLayout groupLayout;
    groupLayout.setSpacing(30);
    groupLayout.addWidget(&lab_group);
    groupLayout.addWidget(&groupBox);

    ElaText lab_name("模型名字:");
    lab_name.setFont(font);
    lab_name.setFixedSize(100, 30);
    ElaLineEdit naemEdit;
    naemEdit.setFixedHeight(30);
    QHBoxLayout naemLayout;
    naemLayout.setSpacing(30);
    naemLayout.addWidget(&lab_name);
    naemLayout.addWidget(&naemEdit);

    ElaText lab_desce("模型描述:");
    lab_desce.setFont(font);
    lab_desce.setFixedSize(100, 30);
    ElaLineEdit desceEdit;
    desceEdit.setFixedHeight(30);
    QHBoxLayout desceLayout;
    desceLayout.setSpacing(30);
    desceLayout.addWidget(&lab_desce);
    desceLayout.addWidget(&desceEdit);

    ElaText lab_location("安装位置:");
    lab_location.setFont(font);
    lab_location.setFixedSize(100, 30);
    ElaLineEdit locationEdit;
    locationEdit.setFixedHeight(30);
    QHBoxLayout locationLayout;
    locationLayout.setSpacing(30);
    locationLayout.addWidget(&lab_location);
    locationLayout.addWidget(&locationEdit);

    ElaText lab_producer("生产厂商:");
    lab_producer.setFont(font);
    lab_producer.setFixedSize(100, 30);
    ElaLineEdit producerEdit;
    producerEdit.setFixedHeight(30);
    QHBoxLayout producerLayout;
    producerLayout.setSpacing(30);
    producerLayout.addWidget(&lab_producer);
    producerLayout.addWidget(&producerEdit);

    ElaText lab_valid("是否禁用:");
    lab_valid.setFont(font);
    lab_valid.setFixedSize(100, 30);
    ElaComboBox validBox;
    validBox.setFixedHeight(30);
    validBox.addItems(QStringList() << "启用" << "禁用");
    QHBoxLayout validLayout;
    validLayout.setSpacing(30);
    validLayout.addWidget(&lab_valid);
    validLayout.addWidget(&validBox);

    ElaText lab_sig("信号模板:");
    lab_sig.setFont(font);
    lab_sig.setFixedSize(100, 30);
    ElaText sigLab;
    sigLab.setFixedHeight(30);
    ElaIconButton btn_select(ElaIconType::FolderOpen);
    btn_select.setFixedSize(30, 30);
    QHBoxLayout sigLayout;
    sigLayout.setSpacing(30);
    sigLayout.addWidget(&lab_sig);
    sigLayout.addWidget(&sigLab);
    sigLayout.addWidget(&btn_select);
    connect(&btn_select, &ElaIconButton::clicked, this, [&](){
        QString fileName = QFileDialog::getOpenFileName(this,
                                                        tr("打开文件"), "",
                                                        tr("Files (*.xlsx);;All Files (*)"));
        sigLab.setText(fileName);
    });

    layout.addLayout(&groupLayout);
    layout.addLayout(&naemLayout);
    layout.addLayout(&desceLayout);
    layout.addLayout(&locationLayout);
    layout.addLayout(&producerLayout);
    layout.addLayout(&validLayout);
    layout.addLayout(&sigLayout);

    UiCustomDialog* dialog = new UiCustomDialog;
    dialog->setConten(&layout);
    while(dialog->exec() == QDialog::Accepted) {
        QString name = naemEdit.text();
        QString desc = desceEdit.text();
        QString location = locationEdit.text();
        QString group = groupBox.currentText();
        QString producer = producerEdit.text();

        if(m_models.contains(name)) {
            QMessageBox::warning(nullptr, "错误", "模型名字重复");
            continue;
        }

        if(name.isEmpty() || desc.isEmpty() || location.isEmpty() || group.isEmpty() || producer.isEmpty()) {
            QMessageBox::warning(nullptr, "错误", "选项不能为空");
            continue;
        }

        bool valid = validBox.currentIndex() == 0 ? true : false;
        QJsonObject config;
        QJsonObject groupicon;
        groupicon["icon"] = 0xf5fd;
        groupicon["family"] = 2;
        groupicon["color"] = "#63E6BE";
        config["groupicon"] = groupicon;

        QJsonObject icon;
        icon["icon"] = 0xf51f;
        icon["family"] = 2;
        icon["color"] = "#63E6BE";
        config["icon"] = groupicon;

        QSharedPointer<CModelInfo> info(new CModelInfo);
        info->user = CUserInfoMgr::ins().info().userid;
        info->name = name;
        info->descr = desc;
        info->location = location;
        info->grouping = group;
        info->sn = 1;
        info->producer = producer;
        info->valid = valid;
        info->configs = config;
        info->create_time = QDateTime::currentDateTime();
        info->update_time = QDateTime::currentDateTime();

        if(!CWebRequestApi::ins().addModel(info)) {
            QMessageBox::warning(nullptr, "错误", "模型添加失败！");
            break;
        }

        m_models.insert(info->name, info);
        viewAddModel(info);
        break;
    }
    dialog->deleteLater();
}

void UiModelTreeView::onImportSig(QString finePath) {
    XLDocument doc;
    doc.open(finePath.toStdString());
    XLWorksheet yxwks = doc.workbook().worksheet("yx");
    XLWorksheet ycwks = doc.workbook().worksheet("yc");
    XLWorksheet ykwks = doc.workbook().worksheet("yk");
    XLWorksheet parameterwks = doc.workbook().worksheet("parameter");

    QJsonObject model;
    model["yxs"] = sheetToJson(yxwks);
    model["ycs"] = sheetToJson(ycwks);
    model["yks"] = sheetToJson(ykwks);
    model["parameters"] = sheetToJson(parameterwks);

    QFile file("./testJson.json");
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        return;
    }
    QTextStream out(&file);
    out <<  QJsonDocument(model).toJson(QJsonDocument::Indented);
    file.close();

    doc.close();
}

QJsonArray UiModelTreeView::sheetToJson(XLWorksheet &yxSheet) {
    struct YxColCfg {
        bool isEnNull = false;
        QString colName;
        EDataType type;
        YxColCfg(){}
        YxColCfg(QString mame, bool pisnull, EDataType ptype) {
            colName = mame;
            isEnNull = pisnull;
            type = ptype;
        }
    };

    QMap<int, YxColCfg> colcfgs;
    for(int col = 1; col <= yxSheet.columnCount(); ++col) {
        QString name = yxSheet.cell(1, col).value().getString().c_str();
        EDataType type;
        bool isEnNull = false;
        if("name" == name || "descr" == name || "groupings" == name || "configs" == name
            || "off_desc" == name || "on_desc" == name
            || "alarm_up_limit_desc" == name || "alarm_down_limit_desc" == name || "datatype" == name)
        {
            type = EDataType::Type_String;
            if("configs" == name)
                isEnNull = true;
        }
        else if("reverse" == name
                || "en_alarm" == name
                || "en_write" == name
                || "en_read" == name)
        {
            type = EDataType::Type_Bool;
        }
        else if("base" == name || "coef" == name || "alarm_up_limit" == name || "alarm_down_limit" == name)
        {
            type = EDataType::Type_Float;
        }
        else
        {
            type = EDataType::Type_Int;
        }
        colcfgs.insert(col, YxColCfg(name, isEnNull, type));
    }

    QJsonArray array;
    for(int row = 2; row <= yxSheet.rowCount(); ++row) {
        QJsonObject obj;
        for(int col = 1; col < yxSheet.columnCount(); ++col){
            XLCellValue value = yxSheet.cell(row, col).value();
            YxColCfg cfg = colcfgs.value(col);

            if(cfg.isEnNull) {
                if(value.getString().empty()) {
                    obj[cfg.colName] = QJsonValue();
                    continue;
                }
            }

            switch (cfg.type) {
            case EDataType::Type_String:
                obj[cfg.colName] = value.getString().c_str();
                break;
            case EDataType::Type_Int:
                obj[cfg.colName] = QString(value.getString().c_str()).toInt();
                break;
            case EDataType::Type_Float:
                qDebug() <<  value.typeAsString();
                obj[cfg.colName] = QString(value.getString().c_str()).toFloat();
                break;
            case EDataType::Type_Bool:
                obj[cfg.colName] = value.get<bool>();
                break;
            default:
                obj[cfg.colName] = QJsonValue();
                break;
            }
        }
        array.append(obj);
    }
    return array;
}

void UiModelTreeView::viewAddModel(QSharedPointer<CModelInfo> &model)
{
    QStandardItem* rootitemptr = nullptr;
    for(int row = 0; row < m_viewModel->rowCount(); ++row) {
        QString name = m_viewModel->item(row)->data(Qt::DisplayRole).toString();
        if(name == model->grouping) {
            rootitemptr = m_viewModel->item(row);
        }
    }

    IconHelper* iconMgr = IconHelper::instance();
    if(!rootitemptr) {
        QString color = model->configs.value("groupicon").toObject().value("color").toString();
        IconHelper::EFonts fontfamily = static_cast<IconHelper::EFonts>(model->configs.value("groupicon").toObject().value("family").toInt());
        int pixcode = model->configs.value("groupicon").toObject().value("icon").toInt();

        QPixmap pix = iconMgr->getPixmap(QColor::fromString(color),fontfamily ,pixcode, 22, 24, 24);
        QStandardItem* rootitem = new QStandardItem(model->grouping);
        rootitem->setData(QVariant(Root), ENodeValueRole::NodelLevel);
        rootitem->setData(QVariant(pix), ENodeValueRole::NodeIcon);
        rootitem->setIcon(QIcon(pix));
        m_viewModel->appendRow(rootitem);
        rootitemptr = rootitem;
    }

    QString color = model->configs.value("icon").toObject().value("color").toString();
    IconHelper::EFonts fontfamily = static_cast<IconHelper::EFonts>(model->configs.value("icon").toObject().value("family").toInt());
    int pixcode = model->configs.value("icon").toObject().value("icon").toInt();

    QPixmap iconpix = iconMgr->getPixmap(QColor::fromString(color),fontfamily ,pixcode, 18, 20, 20);

    QStandardItem* chitem = new QStandardItem(model->name);
    chitem->setData(QVariant::fromValue(model), ENodeValueRole::Model);
    chitem->setData(QVariant(Node_Level_1), ENodeValueRole::NodelLevel);
    chitem->setData(QVariant(iconpix), ENodeValueRole::NodeIcon);
    chitem->setIcon(QIcon(iconpix));
    rootitemptr->appendRow(chitem);
}

UiModelTreeItemDelegate::UiModelTreeItemDelegate(QTreeView *treeView, QObject *parent):QStyledItemDelegate(parent), m_treeView(treeView) {
    IconHelper* iconMgr = IconHelper::instance();

    m_mode = MaxSize;
    m_modeWidth = 98;
    m_rootSpacing = 6;
    m_rootHoaver = QColor(242, 242, 249, 85);
    m_rootNoHoaver = QColor(242, 242, 249);
    m_backGroundColor = QColor(255, 255, 255, 100);
    m_rootTextColor = QColor(22, 22, 20);
    m_expandIconSize = QSize(26, 26);
    m_expandIcon = iconMgr->getPixmap(QColor::fromString("#63E6BE"),IconHelper::FontAwesome6Solid ,0xf0d7, 23, 26, 26);
    m_foldIcon = iconMgr->getPixmap(QColor::fromString("#63E6BE"),IconHelper::FontAwesome6Solid ,0xf0d8, 23, 26, 26);

    m_oneHoaver = QColor(242, 242, 249, 80);
    m_oneNoHoaver = QColor(242, 242, 249);
    m_oneIconDir = true;
}

void UiModelTreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    IconHelper* iconMgr = IconHelper::instance();
    painter->setRenderHint(QPainter::Antialiasing, true);
    painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
    painter->setRenderHint(QPainter::TextAntialiasing, true);

    if (!m_treeView)
        return;

    bool bExpanded = m_treeView->isExpanded(index);

    UiModelTreeView::ENodelLevel level = index.data(UiModelTreeView::ENodeValueRole::NodelLevel).value<UiModelTreeView::ENodelLevel>();
    //QPixmap nodeicon = iconMgr->getPixmap(QColor::fromString("#63E6BE"),IconHelper::FontAwesome6Solid ,0xf5fd, 18, 20, 20);
    QPixmap nodeicon = index.data(UiModelTreeView::ENodeValueRole::NodeIcon).value<QPixmap>();
    QString text =  index.data(Qt::DisplayRole).toString();

    if(UiModelTreeView::ENodelLevel::Root == level) {
        //qDebug() << "rect x=" << option.rect.x() << ", y=" << option.rect.y() << ", w=" << option.rect.width() << ", h=" << option.rect.height();
        painter->save();
        painter->setPen(Qt::NoPen);
        QRect rect = QRect(option.rect.x(), option.rect.y()+m_rootSpacing/2, option.rect.width(), option.rect.height()-m_rootSpacing);
        painter->setBrush((option.state & QStyle::State_MouseOver) ? m_rootHoaver : m_rootNoHoaver);
        painter->drawRoundedRect(rect, 10, 10);
        painter->restore();

        m_mode = (option.rect.width() <= m_modeWidth) ? MiniSize : MaxSize;

        int iconX = 0;
        int iconY = 0;

        if(m_mode == MaxSize) {
            painter->save();
            QFontMetrics fontMetrics(m_rootFont);
            int maxWidth = option.rect.width() - 40 - m_expandIconSize.width() - nodeicon.width();
            QString elidedText = fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
            int x = option.rect.x() + 20 + nodeicon.width();
            int y = option.rect.y()+(m_rootNodeHeight-m_rootSpacing - fontMetrics.height())/2+fontMetrics.height()+m_rootSpacing/2-2;

            iconX = option.rect.x()+10;
            iconY = option.rect.y()+m_rootSpacing/2+(m_rootNodeHeight - nodeicon.height() - m_rootSpacing)/2;

            painter->setBrush(m_rootTextColor);
            painter->setFont(m_rootFont);
            painter->setPen(QPen(m_rootTextColor));
            painter->drawText(x, y, elidedText);
            painter->restore();


            y = (m_rootNodeHeight - m_rootSpacing - m_expandIconSize.height())/2+option.rect.y()+m_rootSpacing/2;
            x = option.rect.x()+option.rect.width()-10-m_expandIconSize.width();
            painter->drawPixmap(x, y, bExpanded ? m_expandIcon : m_foldIcon);
        } else {
            iconX = (option.rect.width() - nodeicon.width())/2 + option.rect.x();
            iconY = (option.rect.height() - nodeicon.height())/2 + option.rect.y();
        }
        //qDebug() << "iconRect x=" << iconX << ", y=" << iconY << ", w=" << nodeicon.width() << ", h=" << nodeicon.height();

        painter->save();
        painter->drawPixmap(iconX, iconY, nodeicon);
        painter->restore();

    }else if(UiModelTreeView::ENodelLevel::Node_Level_1 == level){
        /*根据节点类型绘制背景*/
        UiModelTreeView::ENodeTopEndFlag flag = index.data(UiModelTreeView::ENodeValueRole::NodeTopAndEndFlag).value<UiModelTreeView::ENodeTopEndFlag>();
        painter->save();
        painter->setPen(Qt::NoPen);
        painter->setBrush((option.state & QStyle::State_MouseOver) ? m_oneHoaver : m_oneNoHoaver);
        if(UiModelTreeView::ENodeTopEndFlag::TopNode == flag) {
            painter->drawRoundedRect(option.rect, 10, 10);
            painter->drawRect(option.rect.x(), option.rect.y()+20, option.rect.width(), option.rect.height()-20);
        } else if(UiModelTreeView::ENodeTopEndFlag::EndNode == flag) {
            painter->drawRect(option.rect.x(), option.rect.y(), option.rect.width(), option.rect.height()-10);
            painter->drawRoundedRect(option.rect.x(),option.rect.y()+option.rect.height()-20,option.rect.width(), 20, 10, 10);
        } else {
            painter->drawRect(option.rect);
        }
        painter->restore();

        /*绘制图标,根据m_oneIconDir决定在左侧绘制图标还是右侧*/

        int fontX, fontY, iconX, iconY;
        if(m_oneIconDir) {
            painter->save();
            QFontMetrics fontMetrics(m_oneFont);
            int maxWidth = option.rect.width() - 30 - nodeicon.width();
            QString elidedText = fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);

            fontX = option.rect.x() + 20 + nodeicon.width();
            fontY = option.rect.y()+(m_oneNodeHeight - fontMetrics.height())/2+fontMetrics.height()-2;

            painter->setBrush(m_rootTextColor);
            painter->setFont(m_rootFont);
            painter->setPen(QPen(m_rootTextColor));
            painter->drawText(fontX, fontY, elidedText);

            iconX = option.rect.x() + 10;
            iconY = option.rect.y() + (option.rect.height() - nodeicon.height())/2;
            painter->setPen(Qt::NoPen);
            painter->setBrush(m_rootTextColor);
            painter->drawPixmap(iconX, iconY, nodeicon);

            painter->restore();
        } else {
            painter->save();
            QFontMetrics fontMetrics(m_oneFont);
            int maxWidth = option.rect.width() - 30 - nodeicon.width();
            QString elidedText = fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);

            fontX = option.rect.x() + 20 + nodeicon.width();
            fontY = option.rect.y()+(m_oneNodeHeight - fontMetrics.height())/2+fontMetrics.height()-2;

            painter->setBrush(m_rootTextColor);
            painter->setFont(m_rootFont);
            painter->setPen(QPen(QColor(Qt::white)));
            painter->drawText(fontX, fontY, elidedText);

            iconX = option.rect.x() + 10;
            iconY = option.rect.y() + (option.rect.height() - nodeicon.height())/2;
            painter->setPen(Qt::NoPen);
            painter->setBrush(m_rootTextColor);
            painter->drawPixmap(iconX, iconY, nodeicon);

            painter->restore();
        }
    }

    if(bExpanded) {
        if(UiModelTreeView::ENodelLevel::Root == level) {

        }else if(UiModelTreeView::ENodelLevel::Node_Level_1 == level){

        }
    } else {
        if(UiModelTreeView::ENodelLevel::Root == level) {

        }else if(UiModelTreeView::ENodelLevel::Node_Level_1 == level){
            if(UiModelTreeView::ENodelLevel::Root == level) {

            }else if(UiModelTreeView::ENodelLevel::Node_Level_1 == level){

            }
        }
    }
}

QSize UiModelTreeItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
    UiModelTreeView::ENodelLevel level = index.data(UiModelTreeView::ENodeValueRole::NodelLevel).value<UiModelTreeView::ENodelLevel>();
    if(UiModelTreeView::ENodelLevel::Root == level) {
        if(MiniSize == m_mode)
            return QSize(m_rootNodeHeight, m_rootNodeHeight);

        return QSize(option.rect.width(), m_rootNodeHeight);
    } else if(UiModelTreeView::ENodelLevel::Node_Level_1 == level){
        return QSize(option.rect.width(), m_oneNodeHeight);
    }
    return option.rect.size();
}

bool UiModelTreeItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{

}
